package com.dz.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.dz.constant.MessageConstant;
import com.dz.constant.RabbitMQConstant;
import com.dz.constant.StatusConstant;
import com.dz.constant.SystemConstant;
import com.dz.dto.DishDTO;
import com.dz.dto.DishPageQueryDTO;
import com.dz.entity.Dish;
import com.dz.entity.DishFlavor;
import com.dz.entity.SetMeal;
import com.dz.enumeration.AppHttpCodeEnum;
import com.dz.exception.SystemException;
import com.dz.mapper.DishFlavorMapper;
import com.dz.mapper.DishMapper;
import com.dz.mapper.SetMealMapper;
import com.dz.mapper.SetmealDishMapper;
import com.dz.result.Result;
import com.dz.service.DishService;
import com.dz.utils.BeanCopyUtils;
import com.dz.vo.DishVO;
import com.dz.vo.PageVo;
import io.jsonwebtoken.lang.Assert;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * @author 鄧浩奇
 * @classname DishServiceImpl
 * @description
 * @since 2023/12/21 19:17
 **/
@Service
public class DishServiceImpl implements DishService {

    private final DishMapper dishMapper;

    private final DishFlavorMapper dishFlavorMapper;

    private final SetmealDishMapper setmealDishMapper;

    private final SetMealMapper setMealMapper;

    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public DishServiceImpl(DishMapper dishMapper, DishFlavorMapper dishFlavorMapper, SetmealDishMapper setmealDishMapper, SetMealMapper setMealMapper, RabbitTemplate rabbitTemplate) {
        this.dishMapper = dishMapper;
        this.dishFlavorMapper = dishFlavorMapper;
        this.setmealDishMapper = setmealDishMapper;
        this.setMealMapper = setMealMapper;
        this.rabbitTemplate = rabbitTemplate;
    }

    /*
     * 菜品分页
     * */
    @Override
    public PageVo page(DishPageQueryDTO queryDTO) {
        PageHelper.startPage(queryDTO.getPage(), queryDTO.getPageSize());
        Page<DishVO> dishList = dishMapper.getPage(queryDTO);
        return new PageVo(dishList.getResult(), dishList.getTotal());
    }


    /*
     * 根据id查询
     * */
    @Override
    public DishVO getById(Long id) {
        // 查询菜品信息
        Dish dish = dishMapper.selectDishById(id);
        // 查询菜品口味
        List<DishFlavor> dishFlavors = dishFlavorMapper.getFlavorByDishId(id);
        DishVO dishVO = BeanCopyUtils.copyBean(dish, DishVO.class);
        dishVO.setFlavors(dishFlavors);
        return dishVO;
    }


    /*
     * 修改菜品 (应该开启事务)
     * */
    @Override
    public Result<String> updateById(DishDTO dishDTO) {
        Dish dish = BeanCopyUtils.copyBean(dishDTO, Dish.class);
        // 修改菜品数据
        Integer update = dishMapper.update(dish);

        // 删除原有口味
        dishFlavorMapper.deleteByDishId(dishDTO.getId());

        // 重新插入口味
        insertFlavor(dishDTO, dishDTO.getId());

        if (update.equals(StatusConstant.UPDATE_ERROR)) return Result.error(AppHttpCodeEnum.UPDATE_ERROR.getMsg());
        rabbitTemplate.convertAndSend(RabbitMQConstant.SKY_EXCHANGE,RabbitMQConstant.SKY_Long_ROUTING_KEY,dishDTO.getId());
        return Result.success();
    }


    /*
     * 新增菜品
     * */
    @Override
    public Result<String> insert(DishDTO dishDTO) {
        // 菜品表写入
        Dish dish = BeanCopyUtils.copyBean(dishDTO, Dish.class);
        dishMapper.insert(dish);
        // 口味表写入
        insertFlavor(dishDTO, dish.getId());
        return Result.success();
    }

    private void insertFlavor(DishDTO dishDTO, Long id) {
        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (!flavors.isEmpty()) {
            // 当没选口味时不执行插入
            List<DishFlavor> collect = flavors.stream().filter(item -> !item.getValue().equals(SystemConstant.NULL_VALUE)).toList();
            if (!collect.isEmpty()) {
                collect.forEach(flavor -> flavor.setDishId(id)); // dish.getId() 获取由 useGeneratedKeys 返回回来的主键
                dishFlavorMapper.insertBatch(collect);
            }
        }
    }


    /*
     * 根据id删除
     * */
    @Transactional
    @Override
    public Result<String> deleteByIds(List<Long> ids) {
        Assert.notEmpty(ids, AppHttpCodeEnum.DISH_IDS_IS_NULL.getMsg());

        // 判断 被删除菜品是否是起售状态
        List<Long> notAvailableIdList = ids.stream().filter(id -> dishMapper.selectDishById(id).getStatus().equals(StatusConstant.DISABLE)).toList();

        // 起售状态的套餐无法删除
        if (notAvailableIdList.isEmpty()) return Result.error(MessageConstant.DISH_ON_SALE);

        // 要判断菜品在不在套餐里面
        List<Long> canDeleteIdList = notAvailableIdList.stream().filter(id -> Objects.isNull(dishMapper.isIntoSetmeal(id))).toList();
        if (canDeleteIdList.isEmpty()) return Result.error(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);

        // 删除菜品下的口味
        List<Long> list = ids.stream().filter(id -> {
            List<DishFlavor> dishFlavorList = dishFlavorMapper.getFlavorByDishId(id);
            return Objects.nonNull(dishFlavorList) && !dishFlavorList.isEmpty();
        }).toList();

        // 若存在口味则删除菜品对应的口味
        if (list.isEmpty()){
            return Result.success();
        }

        Integer delFlavor = dishFlavorMapper.deleteBatch(list);
        if (Objects.equals(delFlavor, StatusConstant.DELETE_ERROR))
            throw new RuntimeException(AppHttpCodeEnum.FLAVOR_ID_ERROR.getMsg());

        // 删除菜品
        Integer delDish = dishMapper.deleteBatch(canDeleteIdList);
        rabbitTemplate.convertAndSend(RabbitMQConstant.SKY_EXCHANGE,RabbitMQConstant.SKY_List_ROUTING_KEY,canDeleteIdList);
        if (delDish.equals(StatusConstant.DELETE_ERROR)) throw new SystemException(AppHttpCodeEnum.DELETE_ERROR);

        if (!canDeleteIdList.equals(ids))
            // 仅删除了能未起售和不在套餐下的菜品
            return Result.error(MessageConstant.DISH_ON_SALE_ONLY_DEL_PART);
        else
            return Result.success();
    }


    /*
     * 修改菜品状态 0:停用 1:启用
     * */
    @Override
    public Result<String> changeStatus(Long id, Integer status) {
        Dish dish = Dish.builder().status(status).id(id).build();
        // 根据菜品 id 查询套餐信息
        switch (status) {

            // 当前为停用状态，需要改为起售状态
            case 1 -> dishMapper.changeStatus(dish);

            // 当前为启用状态，需要改为停用状态
            case 0 -> {
                // 根据dishId查询setmealId,根据setmealId 查询套餐集合
                List<SetMeal> setMeals = setmealDishMapper.selectSetmealByDishId(id);
                if (setMeals.isEmpty()) {
                    dishMapper.changeStatus(dish);
                    return Result.success();
                }
                // 遍历集合，过滤出启用状态的套餐
                List<SetMeal> enableSetmealList = setMeals.stream().filter(setMeal -> setMeal.getStatus().equals(StatusConstant.ENABLE)).toList();

                if (enableSetmealList.isEmpty()) {
                    // 包含该菜品的所有套餐都是停售状态，可以将该菜品停售
                    dishMapper.changeStatus(dish);
                } else {
                    // 将启用状态的套餐设置为停用状态
                    enableSetmealList.forEach(setMeal -> {
                        setMeal.setStatus(StatusConstant.DELETE_ERROR);
                        setMealMapper.updateStatus(setMeal);
                    });
                    dishMapper.changeStatus(dish);
                    return Result.okResult(MessageConstant.DISH_STATUS_SUCCESS);
                }
            }
            default -> throw new SystemException(AppHttpCodeEnum.DATA_ERROR);
        }
        rabbitTemplate.convertAndSend(RabbitMQConstant.SKY_EXCHANGE,RabbitMQConstant.SKY_Long_ROUTING_KEY,id);
        return Result.success();
    }


    /*
     * 根据分类id查询菜品
     * */
    @Override
    public List<Dish> getByCategoryId(Long categoryId) {
        return dishMapper.selectByCategoryId(categoryId);
    }


    /*
    * 根据分类id查询菜品包括口味
    * */
    @Override
    public List<DishVO> getDishVoByCategoryId(Long categoryId) {
        Assert.notNull(categoryId,AppHttpCodeEnum.CATEGORY_ID_IS_NULL.getMsg());
        return dishMapper.selectDishVoByCategoryId(categoryId);
    }
}
